/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#pragma once


#include "../绘图框架.h"

#include "Core/Vk结构声明.h"
#include "帧缓存/S_Vk帧缓存.h"
#include "帧缓存/绘制命令缓存.h"
#include "线管绘制.h"

#include <Windows.h>
#include <vulkan/vulkan.h>
#include <vulkan/vulkan_win32.h>

#include <vector>
#include <map>



typedef struct {
	VkPhysicalDeviceMemoryProperties		m_内存属性;
	VkPhysicalDeviceProperties				m_设备属性;

	VkPhysicalDeviceRayTracingPropertiesNV	m_光追设备属性;

	uint32								m_多次采样最大值;
	uint32								m_最大几何输出顶点;
	uint32								m_3D纹理最大分辨率;
	bool								m_支持光追;
}S_物理设备属性;




typedef struct {
	VkDevice						m_设备;
	VkPhysicalDevice				m_物理设备;

	VkPhysicalDeviceProperties			m_设备属性;
	VkPhysicalDeviceMemoryProperties	m_内存属性;

	
	ivec2	绘制面大小;
	uint32	绘图列队家族Offset;
	uint32	交换链列队家族Offset;

	S_Vk帧缓存*		m_交换链帧缓存;
	VkFormat		m_颜色图像格式;
	VkFormat		m_深度图像格式;
	VkRenderPass	m_渲染通道;
	//VkSemaphore		m_清屏信号;
	VkSwapchainKHR	m_交换链;
	VkSurfaceKHR	m_绘制面;
	VkSemaphore		m_图像获取信号量;

	VkClearValue				m_背景清除值[4];
	VkSubmitInfo				m_命令提交信息;
	VkRenderPassBeginInfo		m_开始渲染信息;
	VkCommandBufferBeginInfo	m_命令开始信息;

	
	uint32					m_当前帧ID;
	uint32					m_列队ID;



	VkQueue*				m_图形列队;
	VkCommandPool			m_命令缓存池;
	VkCommandBuffer			m_命令缓存;
	VkFence					m_同步围栏;




	//==================== 多线程环境 ===========================
	VkCommandBuffer					m_二级命令缓存[64];
	VkCommandPool					m_二级命令管道;
	uint16							m_命令缓存数;

	//VkRenderPassBeginInfo			m_渲染通道开始信息;
	//VkCommandBufferBeginInfo		m_主渲染开始信息;

	VkCommandBufferBeginInfo		m_二级渲染开始信息;
	VkCommandBufferInheritanceInfo	m_二级命令缓存继承信息;


	//光追API
	//PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelinesKHR;
	PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructure;
	PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructure;
	PFN_vkCmdBuildAccelerationStructuresKHR vkCmdBuildAccelerationStructures;
	PFN_vkBuildAccelerationStructuresKHR vkBuildAccelerationStructures;
	PFN_vkGetAccelerationStructureBuildSizesKHR vkGetAccelerationStructureBuildSizes;
	PFN_vkGetAccelerationStructureDeviceAddressKHR vkGetAccelerationStructureDeviceAddress;
	PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelines;
	PFN_vkGetRayTracingShaderGroupHandlesKHR vkGetRayTracingShaderGroupHandles;
	PFN_vkCmdTraceRaysKHR vkCmdTraceRays;
	
}S_绘图设备配置;



void f_vkFrame_初始化光追函数指针(S_绘图设备配置* 绘图设备配置);
Inline S_绘图设备配置* f_vk_get绘图环境(S_设备环境& ctx) { return (S_绘图设备配置*)ctx.m_绘图设备配置; }

/*typedef struct {
	VkCommandBuffer					m_二级命令缓存[64];
	VkCommandPool					m_二级命令管道;

	VkCommandBuffer					m_命令缓存;
	VkCommandPool					m_命令缓存池;
	
	
	VkRenderPass					m_渲染通道;



	VkSubmitInfo					m_命令提交信息;
	VkSemaphore						m_图像获取信号量;
	VkFence							m_同步围栏;
	VkCommandBuffer					m_主命令缓存;


	//uint32							m_Type;
	VkRenderPassBeginInfo			m_渲染通道开始信息;
	VkCommandBufferBeginInfo		m_主渲染开始信息;

	VkCommandBufferBeginInfo		m_二级渲染开始信息;
	VkCommandBufferInheritanceInfo	m_二级命令缓存继承信息;
	

	//================== 映射主环境 ===================
	VkDevice						m_设备;
	VkQueue							m_图形列队;
	

	uint16							m_命令缓存数;


	S_绘图设备配置*					m_设备属性;
	S_物理设备属性*					m_硬件属性;
	S_设备环境*						m_临时设备环境_以后替换层绘图环境;
}S_绘图配置;*/






struct S_VK框架 : public S_绘图框架 {
	VkInstance										m_Instance;

	vector<VkPhysicalDeviceMemoryProperties>		m_内存属性;
	vector<VkPhysicalDeviceProperties>				m_物理设备属性;
	vector<VkPhysicalDeviceRayTracingPropertiesNV>	m_物理光追设备属性;

	map<uint32, vector<VkQueueFamilyProperties>>	m_列队家族;


	vector<uint32>									m_绘图GPU;
	vector<uint32>									m_光追GPU;
	map< uint32, vector<S_Vk逻辑设备>>				m_逻辑设备;
	//vector<VkPipeline>								m_线管;
	//vector<string>								m_扩展名称;
	//vector<string>								m_设备名称;
	VkAllocationCallbacks*							m_allocator = VK_NULL_HANDLE;

	bool											m_开启光追;





	S_VK框架();
	~S_VK框架();

	//bool f_initVK();
	bool f_releaseVK();

	//bool	f_检查验证层支持();

	bool	f_创建实例();
	bool	f_枚举物理设备(const vector<const char*>& 光追扩展);
	//bool	f_getGPU(const VkPhysicalDevice& gpu, const std::vector<const char*>& extensions);
	
	int32		f_选择列队族(vector<VkQueueFamilyProperties>& 列队族, uint32 flags);
	VkFormat	f_取设备支持像素格式(VkPhysicalDevice& 物理设备, VkSurfaceKHR& surface);



	virtual S_协处理设备	f_取物理设备(uint8 id);

	S_协处理设备	f_创建图形逻辑设备(S_协处理设备& dev, bool 是否有光追支持);
	S_协处理设备	f_创建计算逻辑设备(S_协处理设备& dev);
	//bool			f_创建窗口绘制面(S_设备环境& dev, HINSTANCE& hInstance, HWND& hWnd, ivec2 size, E_MS次数 采样);
	bool			f_创建窗口绘制面(void* 绘图设备, HINSTANCE& hInstance, HWND& hWnd, ivec2 size, E_MS次数 采样);
	bool			f_创建同步围栏(S_协处理设备& 逻辑dev);
	

	bool			f_创建命令缓存池(S_协处理设备& dev);
	bool			f_创建命令缓存(S_协处理设备& dev, uint32 池ID, uint32 num = 1);
	//bool			f_创建逻辑设备(uint32 物理设备key, const vector<const char*>& extensions);
	

	bool		f_销毁交换链(S_Vk逻辑设备& dev);
	bool		f_销毁命令列队(S_Vk逻辑设备& dev);
	bool		f_销毁逻辑设备(vector<S_Vk逻辑设备>& devs);
	//bool		f_销毁物理设备();
	bool		f_销毁实例(VkInstance& instance);

	bool		f_绘制(S_协处理设备& dev);
	void		f_alloc(S_协处理设备& dev);
	void		f_End(S_协处理设备& dev);
	void		f_alloc(void* 绘图设备配置);
	void		f_End(void* 绘图设备配置);
	//void f_mainLoop();
private:
	vector<VkQueueFamilyProperties>	f_罗列物理设备列队家族(VkPhysicalDevice& 物理设备);

	bool		m_是否有光追支持;

	//bool		f_创建交换链(S_设备环境& dev, ivec2 size, VkSwapchainKHR old_swapchain);
	//void		f_创建交换链绘制缓存(S_协处理设备& dev, E_MS次数 采样);
	//void		f_重置交换链(S_设备环境& dev, ivec2 size, E_MS次数 采样);

	bool		f_创建交换链(void* 绘图设备, ivec2 size, VkSwapchainKHR old_swapchain);
	void		f_创建交换链绘制缓存(void* 绘图设备, E_MS次数 采样);
	void		f_重置交换链(void* 绘图设备, ivec2 size, E_MS次数 采样);

};










void			f_vk创建命令缓存池(S_绘图设备配置* 绘图设备);
VkCommandBuffer	f_vk创建命令缓存(S_绘图设备配置* 绘图设备, uint32 num = 1, bool 创建新池 = false);
void            f_vk销毁命令缓存(S_绘图设备配置* 绘图设备, VkCommandBuffer cmd);

void			f_vk绑定命令缓存(S_绘图设备配置* 绘图设备, VkCommandBuffer cmd, bool 重置命令缓存 = false);
void			f_vk刷新命令缓存(S_绘图设备配置* 绘图设备, VkCommandBuffer cmd, bool 释放命令缓存 = false);


Inline S_结构对象指针 f_vk创建Fence(S_绘图设备配置* 绘图环境) {
	VkFenceCreateInfo fenceCreateInfo{};
	fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
	fenceCreateInfo.flags = 0;

	VkFence fence;
	vkCreateFence(绘图环境->m_设备, &fenceCreateInfo, nullptr, &fence);
	return (S_结构对象指针)fence;
}

Inline void f_vk销毁Fence(S_绘图设备配置* 绘图环境, S_结构对象指针 fence) {
	vkDestroyFence(绘图环境->m_设备, (VkFence)fence, nullptr);
}

void	f_vk创建命令缓存(void* 绘图设备, uint32 池ID, uint32 num = 1);
void	f_vk创建同步围栏(void* 绘图设备);






inline VkDescriptorType f_vk_get缓存布局类型(E_板载缓存类型 缓存类型) {
	switch (缓存类型) {
	case E_板载缓存类型::e_UBO:
		return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
		break;
	case E_板载缓存类型::e_VBO:
	case E_板载缓存类型::e_SSBO:
		return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
		break;
	case E_板载缓存类型::e_SSBOd:
		return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
		//case E_板载缓存类型::e_UBO:
		//	return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;

	case E_板载缓存类型::e_IMAGE: return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
	case E_板载缓存类型::e_SAMPLER: return VK_DESCRIPTOR_TYPE_SAMPLER;
	case E_板载缓存类型::e_SAMPLER_Array:
	case E_板载缓存类型::e_IMAGE_SAMPLER: return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;

	case E_板载缓存类型::e_光追BVH: return VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
	default:
		break;
	}

	return VK_DESCRIPTOR_TYPE_MAX_ENUM;
}



Inline uint32 f_vk_get参数布局着色阶段(E_着色阶段 阶段) {
	
	switch (阶段) {
	case E_着色阶段::e_顶点着色:
		return VK_SHADER_STAGE_VERTEX_BIT;

	case E_着色阶段::e_细分控制着色:
		return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
	
	case E_着色阶段::e_细分着色:
		return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
	
	case E_着色阶段::e_几何着色:
		return VK_SHADER_STAGE_GEOMETRY_BIT;
	
	case E_着色阶段::e_像素着色:
		return VK_SHADER_STAGE_FRAGMENT_BIT;
	
	case E_着色阶段::e_计算着色:
		return VK_SHADER_STAGE_COMPUTE_BIT;
	
	case E_着色阶段::e_光追射线生成:
		return VK_SHADER_STAGE_RAYGEN_BIT_KHR;
	
	case E_着色阶段::e_光追忽略相交:
		return VK_SHADER_STAGE_MISS_BIT_KHR;
	
	case E_着色阶段::e_光追最近相交:
		return VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
	}

	return 0;
}

